#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

using namespace std;

template <class T>
class RingQueue
{
private:
    void P(sem_t& sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t& sem)
    {
        sem_post(&sem);
    }
    void Lock(pthread_mutex_t &mutex)//锁是同一把，要引用
    {
        pthread_mutex_lock(&mutex);
    }
    void UnLock(pthread_mutex_t &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }
public:
    RingQueue(int cap)
        :_cap(cap),_ring_queue(cap),_productor_step(0),_consumer_step(0)
    {
        sem_init(&_room_sem, 0, _cap);
        sem_init(&_data_sem, 0, 0);
        pthread_mutex_init(&_productor_mutex, nullptr);
        pthread_mutex_init(&_consumer_mutex, nullptr);
    }

    void Enqueue(T& in)
    {
        P(_room_sem);//申请空间
        Lock(_productor_mutex);//加锁——先买票再排队，而不是排队去买票
        _ring_queue[_productor_step++] = in;// 生产
        _productor_step %= _cap;
        UnLock(_productor_mutex);//解锁
        V(_data_sem);
    }

    void Pop(T* out)
    {
        P(_data_sem);//申请数据
        Lock(_consumer_mutex);//加锁——先买票再排队，而不是排队去买票
        *out = _ring_queue[_consumer_step++];// 消费
        _consumer_step %= _cap;
        UnLock(_consumer_mutex);//解锁
        V(_room_sem);
    }

    ~RingQueue()
    {
        sem_destroy(&_room_sem);
        sem_destroy(&_data_sem);
        pthread_mutex_destroy(&_productor_mutex);
        pthread_mutex_destroy(&_consumer_mutex);
    }

private:
    vector<T> _ring_queue; // 环形队列
    int _cap; // 容量上限
    int _productor_step; // 生产者下标
    int _consumer_step; // 消费者下标
    sem_t _room_sem; // 空间信号量
    sem_t _data_sem; // 数据信号量
    pthread_mutex_t _productor_mutex; // 生产者的锁
    pthread_mutex_t _consumer_mutex; // 消费者的锁
};